#include "calculation_server.h"
#include "mtmtest.h"
#include "matrix.h"
#include <stdarg.h>

Matrix initMatrix( int rows, int columns, ... )
{
	Matrix result( rows, columns );

	va_list vl;
	va_start( vl, columns );

	for( int r = 1; r <= rows; ++r )
	{
		for( int c = 1; c <= columns; ++c )
		{
			double cell = va_arg(vl,double);
			result(r, c) = cell;
		}
	}

	va_end( vl );

	return result;
}

bool calculationServerTest()
{
	CalculationServer server;
	
	Matrix A = initMatrix(2,2, 1.0, 1.0, 1.0, 0.0);
	Matrix B = initMatrix(4,1, 2.0, 0.0, 1.0, -1.0);
	// Add jobs
	int id0 = server.addJob(CalculationServer::POLYNOMIAL, 50, A, B);
	int id1 = server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM, 50, Matrix::createUnit(4), B);
	int id2 = server.addJob(CalculationServer::SIMILARITY, 80, A, A);

	// Jobs order should be: id2 -> id0 -> id1
	ASSERT_EQUALS(id2, server.nextJob());
	// The following error doesn't change the server's queue:
	ASSERT_THROW(CalculationServer::InvalidPriority, server.changePriority(id2, -10));
	ASSERT_EQUALS(id2, server.nextJob());

	ASSERT_NO_THROW(server.changePriority(id2, 10));
	// Jobs order should be: id0 -> id1 -> id2
	ASSERT_EQUALS(3, server.totalJobs());
	ASSERT_EQUALS(id0, server.nextJob());
	// Jobs order should be: id0 -> id2
	ASSERT_NO_THROW(server.removeJob(id2));
	// Job should not exist on the server:
	ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id2));

	// executing job id0
	ASSERT_EQUALS(id0, server.nextJob());
	Matrix output = server.execute(); 
	Matrix C = initMatrix(2,2, 1.0, -1.0, -1.0, 2.0);
	ASSERT_EQUALS(C, output);
	// executing job id1
	ASSERT_EQUALS(id1, server.nextJob());
	output = server.execute();
	ASSERT_EQUALS(output,B);
	ASSERT_EQUALS(0, server.totalJobs());
	// Server's job queue is empty, the following should throw:
	ASSERT_THROW(CalculationServer::JobNotFound, server.nextJob());
	ASSERT_THROW(CalculationServer::JobNotFound, server.execute());
	return true;
}

int main()
{
	RUN_TEST(calculationServerTest);
	return 0;
}
